import * as fs from 'fs-extra';
import * as path from 'path';
import { FileAnalyzer } from './FileAnalyzer.js';

export interface SpringBootAnalysisResult {
  projectPath: string;
  framework: 'SpringBoot' | 'Spring' | 'Unknown';
  version: string;
  architecture: {
    layerCompliance: LayerCompliance;
    patterns: DetectedPattern[];
    violations: ArchitectureViolation[];
  };
  dependencies: DependencyAnalysis;
  suggestions: SpringBootSuggestion[];
}

export interface LayerCompliance {
  controller: LayerInfo;
  service: LayerInfo;
  repository: LayerInfo;
  entity: LayerInfo;
  config: LayerInfo;
}

export interface LayerInfo {
  exists: boolean;
  fileCount: number;
  compliance: number; // 0-100
  issues: string[];
}

export interface DetectedPattern {
  name: string;
  description: string;
  files: string[];
  confidence: number; // 0-100
}

export interface ArchitectureViolation {
  type: 'layer_mixing' | 'dependency_cycle' | 'wrong_annotation' | 'missing_layer';
  severity: 'high' | 'medium' | 'low';
  description: string;
  files: string[];
  suggestion: string;
}

export interface DependencyAnalysis {
  springBootVersion: string;
  dependencies: Array<{
    name: string;
    version: string;
    usage: 'active' | 'unused' | 'outdated';
  }>;
  securityIssues: Array<{
    dependency: string;
    issue: string;
    severity: 'critical' | 'high' | 'medium' | 'low';
  }>;
}

export interface SpringBootSuggestion {
  category: 'architecture' | 'performance' | 'security' | 'best_practice';
  title: string;
  description: string;
  implementation: string;
  priority: 'high' | 'medium' | 'low';
  estimatedEffort: 'low' | 'medium' | 'high';
}

export class SpringBootRefactorAnalyzer {
  private fileAnalyzer: FileAnalyzer;

  constructor() {
    this.fileAnalyzer = new FileAnalyzer();
  }

  async analyzeProject(projectPath: string): Promise<SpringBootAnalysisResult> {
    const framework = await this.detectFramework(projectPath);
    const version = await this.detectSpringBootVersion(projectPath);
    
    const architecture = await this.analyzeArchitecture(projectPath);
    const dependencies = await this.analyzeDependencies(projectPath);
    const suggestions = await this.generateSuggestions(projectPath, architecture, dependencies);

    return {
      projectPath,
      framework,
      version,
      architecture,
      dependencies,
      suggestions
    };
  }

  async suggestImprovements(projectPath: string): Promise<SpringBootSuggestion[]> {
    const analysis = await this.analyzeProject(projectPath);
    return analysis.suggestions;
  }

  private async detectFramework(projectPath: string): Promise<'SpringBoot' | 'Spring' | 'Unknown'> {
    const pomPath = path.join(projectPath, 'pom.xml');
    const gradlePath = path.join(projectPath, 'build.gradle');
    
    try {
      if (await fs.pathExists(pomPath)) {
        const pomContent = await fs.readFile(pomPath, 'utf-8');
        if (pomContent.includes('spring-boot-starter')) {
          return 'SpringBoot';
        } else if (pomContent.includes('springframework')) {
          return 'Spring';
        }
      }
      
      if (await fs.pathExists(gradlePath)) {
        const gradleContent = await fs.readFile(gradlePath, 'utf-8');
        if (gradleContent.includes('spring-boot-starter')) {
          return 'SpringBoot';
        } else if (gradleContent.includes('springframework')) {
          return 'Spring';
        }
      }
    } catch (error) {
      console.error('检测框架时出错:', error);
    }
    
    return 'Unknown';
  }

  private async detectSpringBootVersion(projectPath: string): Promise<string> {
    const pomPath = path.join(projectPath, 'pom.xml');
    
    try {
      if (await fs.pathExists(pomPath)) {
        const pomContent = await fs.readFile(pomPath, 'utf-8');
        const versionMatch = pomContent.match(/<spring-boot\.version>([^<]+)<\/spring-boot\.version>/);
        if (versionMatch) {
          return versionMatch[1];
        }
        
        const parentVersionMatch = pomContent.match(/<parent>[\s\S]*?<version>([^<]+)<\/version>[\s\S]*?<\/parent>/);
        if (parentVersionMatch) {
          return parentVersionMatch[1];
        }
      }
    } catch (error) {
      console.error('检测SpringBoot版本时出错:', error);
    }
    
    return 'Unknown';
  }

  private async analyzeArchitecture(projectPath: string): Promise<{
    layerCompliance: LayerCompliance;
    patterns: DetectedPattern[];
    violations: ArchitectureViolation[];
  }> {
    const javaFiles = await this.fileAnalyzer.findJavaFiles(projectPath);
    
    // 分析分层架构
    const layerCompliance = await this.analyzeLayerCompliance(javaFiles);
    
    // 检测设计模式
    const patterns = await this.detectDesignPatterns(javaFiles);
    
    // 检查架构违规
    const violations = await this.checkArchitectureViolations(javaFiles);

    return {
      layerCompliance,
      patterns,
      violations
    };
  }

  private async analyzeLayerCompliance(javaFiles: string[]): Promise<LayerCompliance> {
    const layers = {
      controller: { files: [] as string[], issues: [] as string[] },
      service: { files: [] as string[], issues: [] as string[] },
      repository: { files: [] as string[], issues: [] as string[] },
      entity: { files: [] as string[], issues: [] as string[] },
      config: { files: [] as string[], issues: [] as string[] }
    };

    for (const file of javaFiles) {
      const content = await fs.readFile(file, 'utf-8');
      const fileName = path.basename(file);
      
      // Controller层分析
      if (content.includes('@Controller') || content.includes('@RestController') || fileName.includes('Controller')) {
        layers.controller.files.push(file);
        if (!content.includes('@RequestMapping') && !content.includes('@GetMapping')) {
          layers.controller.issues.push(`${fileName}: 缺少请求映射注解`);
        }
        if (content.includes('new ') && !content.includes('@Autowired')) {
          layers.controller.issues.push(`${fileName}: 应使用依赖注入而非new创建对象`);
        }
      }
      
      // Service层分析
      if (content.includes('@Service') || fileName.includes('Service')) {
        layers.service.files.push(file);
        if (content.includes('SELECT') || content.includes('INSERT')) {
          layers.service.issues.push(`${fileName}: Service层不应包含SQL语句`);
        }
      }
      
      // Repository层分析
      if (content.includes('@Repository') || content.includes('@Mapper') || fileName.includes('Repository') || fileName.includes('Dao')) {
        layers.repository.files.push(file);
        if (content.includes('business') || content.includes('calculate')) {
          layers.repository.issues.push(`${fileName}: Repository层不应包含业务逻辑`);
        }
      }
      
      // Entity层分析
      if (content.includes('@Entity') || content.includes('@Table') || fileName.includes('Entity') || fileName.includes('Model')) {
        layers.entity.files.push(file);
        if (content.includes('public void set') && !content.includes('private')) {
          layers.entity.issues.push(`${fileName}: 实体类字段应为private`);
        }
      }
      
      // Config层分析
      if (content.includes('@Configuration') || fileName.includes('Config')) {
        layers.config.files.push(file);
      }
    }

    return {
      controller: {
        exists: layers.controller.files.length > 0,
        fileCount: layers.controller.files.length,
        compliance: this.calculateCompliance(layers.controller),
        issues: layers.controller.issues
      },
      service: {
        exists: layers.service.files.length > 0,
        fileCount: layers.service.files.length,
        compliance: this.calculateCompliance(layers.service),
        issues: layers.service.issues
      },
      repository: {
        exists: layers.repository.files.length > 0,
        fileCount: layers.repository.files.length,
        compliance: this.calculateCompliance(layers.repository),
        issues: layers.repository.issues
      },
      entity: {
        exists: layers.entity.files.length > 0,
        fileCount: layers.entity.files.length,
        compliance: this.calculateCompliance(layers.entity),
        issues: layers.entity.issues
      },
      config: {
        exists: layers.config.files.length > 0,
        fileCount: layers.config.files.length,
        compliance: this.calculateCompliance(layers.config),
        issues: layers.config.issues
      }
    };
  }

  private calculateCompliance(layer: { files: string[], issues: string[] }): number {
    if (layer.files.length === 0) return 100;
    const issueRate = layer.issues.length / layer.files.length;
    return Math.max(0, Math.round((1 - issueRate) * 100));
  }

  private async detectDesignPatterns(javaFiles: string[]): Promise<DetectedPattern[]> {
    const patterns: DetectedPattern[] = [];
    
    for (const file of javaFiles) {
      const content = await fs.readFile(file, 'utf-8');
      const fileName = path.basename(file);
      
      // 检测单例模式
      if (content.includes('private static') && content.includes('getInstance')) {
        patterns.push({
          name: 'Singleton',
          description: '单例模式实现',
          files: [file],
          confidence: 85
        });
      }
      
      // 检测工厂模式
      if (fileName.includes('Factory') || content.includes('create') && content.includes('return new')) {
        patterns.push({
          name: 'Factory',
          description: '工厂模式实现',
          files: [file],
          confidence: 75
        });
      }
      
      // 检测策略模式
      if (content.includes('interface') && content.includes('Strategy')) {
        patterns.push({
          name: 'Strategy',
          description: '策略模式实现',
          files: [file],
          confidence: 80
        });
      }
      
      // 检测观察者模式
      if (content.includes('@EventListener') || content.includes('Observer')) {
        patterns.push({
          name: 'Observer',
          description: '观察者模式实现',
          files: [file],
          confidence: 90
        });
      }
    }
    
    return patterns;
  }

  private async checkArchitectureViolations(javaFiles: string[]): Promise<ArchitectureViolation[]> {
    const violations: ArchitectureViolation[] = [];
    
    for (const file of javaFiles) {
      const content = await fs.readFile(file, 'utf-8');
      const fileName = path.basename(file);
      
      // 检查Controller直接调用Repository
      if (content.includes('@Controller') || content.includes('@RestController')) {
        if (content.includes('@Autowired') && content.includes('Repository')) {
          violations.push({
            type: 'layer_mixing',
            severity: 'high',
            description: 'Controller层直接依赖Repository层，违反分层架构',
            files: [file],
            suggestion: '应通过Service层访问Repository'
          });
        }
      }
      
      // 检查Entity包含业务逻辑
      if (content.includes('@Entity')) {
        if (content.includes('calculate') || content.includes('validate') || content.includes('process')) {
          violations.push({
            type: 'layer_mixing',
            severity: 'medium',
            description: 'Entity包含业务逻辑，应保持纯数据对象',
            files: [file],
            suggestion: '将业务逻辑移至Service层'
          });
        }
      }
      
      // 检查缺少必要注解
      if (fileName.includes('Service') && !content.includes('@Service')) {
        violations.push({
          type: 'wrong_annotation',
          severity: 'medium',
          description: 'Service类缺少@Service注解',
          files: [file],
          suggestion: '添加@Service注解以启用Spring管理'
        });
      }
      
      if (fileName.includes('Repository') && !content.includes('@Repository') && !content.includes('@Mapper')) {
        violations.push({
          type: 'wrong_annotation',
          severity: 'medium',
          description: 'Repository类缺少@Repository或@Mapper注解',
          files: [file],
          suggestion: '添加相应注解以启用Spring管理'
        });
      }
    }
    
    return violations;
  }

  private async analyzeDependencies(projectPath: string): Promise<DependencyAnalysis> {
    const pomPath = path.join(projectPath, 'pom.xml');
    let springBootVersion = 'Unknown';
    const dependencies: Array<{ name: string; version: string; usage: 'active' | 'unused' | 'outdated' }> = [];
    const securityIssues: Array<{ dependency: string; issue: string; severity: 'critical' | 'high' | 'medium' | 'low' }> = [];
    
    try {
      if (await fs.pathExists(pomPath)) {
        const pomContent = await fs.readFile(pomPath, 'utf-8');
        
        // 提取SpringBoot版本
        const versionMatch = pomContent.match(/<version>([^<]+)<\/version>/);
        if (versionMatch) {
          springBootVersion = versionMatch[1];
        }
        
        // 分析依赖
        const depMatches = pomContent.matchAll(/<dependency>[\s\S]*?<groupId>([^<]+)<\/groupId>[\s\S]*?<artifactId>([^<]+)<\/artifactId>[\s\S]*?<version>([^<]+)<\/version>[\s\S]*?<\/dependency>/g);
        
        for (const match of depMatches) {
          const groupId = match[1];
          const artifactId = match[2];
          const version = match[3];
          const fullName = `${groupId}:${artifactId}`;
          
          dependencies.push({
            name: fullName,
            version,
            usage: 'active' // 简化实现，实际应检查使用情况
          });
          
          // 检查已知安全问题
          if (this.hasKnownSecurityIssues(fullName, version)) {
            securityIssues.push({
              dependency: fullName,
              issue: '包含已知安全漏洞',
              severity: 'high'
            });
          }
        }
      }
    } catch (error) {
      console.error('分析依赖时出错:', error);
    }
    
    return {
      springBootVersion,
      dependencies,
      securityIssues
    };
  }

  private hasKnownSecurityIssues(dependency: string, version: string): boolean {
    // 简化实现，实际应查询CVE数据库
    const knownIssues = [
      'org.springframework:spring-core:4.3.0',
      'org.apache.struts:struts2-core:2.3.16'
    ];
    
    return knownIssues.some(issue => dependency.includes(issue.split(':')[1]));
  }

  private async generateSuggestions(
    projectPath: string, 
    architecture: any, 
    dependencies: DependencyAnalysis
  ): Promise<SpringBootSuggestion[]> {
    const suggestions: SpringBootSuggestion[] = [];
    
    // 架构改进建议
    if (!architecture.layerCompliance.service.exists) {
      suggestions.push({
        category: 'architecture',
        title: '添加Service层',
        description: '项目缺少Service层，建议添加以实现业务逻辑分离',
        implementation: '创建Service接口和实现类，使用@Service注解',
        priority: 'high',
        estimatedEffort: 'medium'
      });
    }
    
    if (architecture.violations.length > 0) {
      suggestions.push({
        category: 'architecture',
        title: '修复架构违规',
        description: `发现${architecture.violations.length}个架构违规问题`,
        implementation: '按照分层架构原则重构代码',
        priority: 'high',
        estimatedEffort: 'high'
      });
    }
    
    // 性能优化建议
    suggestions.push({
      category: 'performance',
      title: '启用缓存',
      description: '添加Spring Cache支持以提升性能',
      implementation: '添加@EnableCaching和@Cacheable注解',
      priority: 'medium',
      estimatedEffort: 'low'
    });
    
    suggestions.push({
      category: 'performance',
      title: '配置连接池',
      description: '优化数据库连接池配置',
      implementation: '配置HikariCP参数',
      priority: 'medium',
      estimatedEffort: 'low'
    });
    
    // 安全建议
    if (dependencies.securityIssues.length > 0) {
      suggestions.push({
        category: 'security',
        title: '修复安全漏洞',
        description: `发现${dependencies.securityIssues.length}个安全问题`,
        implementation: '升级相关依赖版本',
        priority: 'high',
        estimatedEffort: 'low'
      });
    }
    
    suggestions.push({
      category: 'security',
      title: '添加安全配置',
      description: '添加Spring Security配置',
      implementation: '配置认证和授权机制',
      priority: 'medium',
      estimatedEffort: 'medium'
    });
    
    // 最佳实践建议
    suggestions.push({
      category: 'best_practice',
      title: '添加全局异常处理',
      description: '实现统一的异常处理机制',
      implementation: '使用@ControllerAdvice创建全局异常处理器',
      priority: 'medium',
      estimatedEffort: 'low'
    });
    
    suggestions.push({
      category: 'best_practice',
      title: '添加API文档',
      description: '集成Swagger生成API文档',
      implementation: '添加springdoc-openapi依赖',
      priority: 'low',
      estimatedEffort: 'low'
    });
    
    suggestions.push({
      category: 'best_practice',
      title: '添加健康检查',
      description: '启用Spring Boot Actuator',
      implementation: '添加actuator依赖和配置',
      priority: 'low',
      estimatedEffort: 'low'
    });
    
    return suggestions;
  }
}